package com.frank.loadinglibrary.common.gear;

import com.frank.loadinglibrary.base.baseanimations.BaseAnimationController;
import com.frank.loadinglibrary.base.baseelement.BaseElement;
import com.frank.loadinglibrary.base.baseelement.IComponentCallback;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.utils.Color;

import java.util.ArrayList;

/**
 * @author SUQI
 * @date 2021/6/9
 * @description 齿轮
 **/
public class GearElement extends BaseElement implements BaseAnimationController.IAnimationController<AnimatorValue> {

    private Paint outerPaint;
    private Paint innerPaint;
    private Paint gearPaint;
    private Color teethColor;
    private Color outerCircleColor;
    private Color innerCircleColor;

    private float outerCircleRadius;
    private float innerCircleRadius;
    private float innerCircleRadiusPercent = 2 / 15f;
    private float outerCircleRadiusPercent = 1 / 5f;
    private int teethCount = 10;
    private int teethTopWith = 10;

    private float rotateAngle = 0;
    private int duration;

    private GearElement(IComponentCallback iComponentCallback) {
        callback = iComponentCallback;
    }

    @Override
    public ArrayList<AnimatorValue> onCreateAnimators() {
        ArrayList<AnimatorValue> list = new ArrayList<>();
        AnimatorValue animatorValue = new AnimatorValue();
        animatorValue.setDuration(duration);
        animatorValue.setLoopedCount(Animator.INFINITE);
        animatorValue.setValueUpdateListener((animatorValue1, v) -> {
            rotateAngle = 360 * v;
            callback.reflushComponent();
        });
        list.add(animatorValue);
        return list;
    }

    @Override
    public void onAnimationReset() {
        //do nothing because donot need to reset animation params
    }

    @Override
    public BaseAnimationController.IAnimationController<AnimatorValue> initAnimationController() {
        return this;
    }

    @Override
    public void initPaint() {
        super.initPaint();
        outerPaint = new Paint();
        outerPaint.setAntiAlias(true);
        outerPaint.setStyle(Paint.Style.FILL_STYLE);
        outerPaint.setColor(outerCircleColor);

        innerPaint = new Paint();
        innerPaint.setAntiAlias(true);
        innerPaint.setStyle(Paint.Style.FILL_STYLE);
        innerPaint.setColor(innerCircleColor);

        gearPaint = new Paint();
        gearPaint.setStyle(Paint.Style.FILL_STYLE);
        gearPaint.setAntiAlias(true);
        gearPaint.setColor(teethColor);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        outerCircleRadius = getWidth() * outerCircleRadiusPercent;
        innerCircleRadius = getWidth() * innerCircleRadiusPercent;
        changeLocation(canvas, -innerCircleRadius - teethTopWith / 2f, -innerCircleRadius - teethTopWith / 2f, -rotateAngle);
        changeLocation(canvas, innerCircleRadius + teethTopWith / 2f, innerCircleRadius + teethTopWith / 2f, rotateAngle);
    }

    private void changeLocation(Canvas canvas, float translateX, float translateY, float angle) {
        canvas.save();
        canvas.translate(translateX, translateY);
        canvas.rotate(angle, getWidth() / 2, getHeight() / 2);
        drawTeeth(canvas);
        canvas.restore();
    }

    private void drawTeeth(Canvas canvas) {
        Path path = new Path();
        double degree = Math.PI / (teethCount * 2);
        path.moveTo((float) (getWidth() / 2 - outerCircleRadius * Math.sin(degree)), getHeight() / 2);
        path.lineTo((float) (getWidth() / 2 + outerCircleRadius * Math.sin(degree)), getHeight() / 2);
        path.lineTo((float) (getWidth() / 2 + outerCircleRadius * Math.sin(degree)), getHeight() / 2 - outerCircleRadius - teethTopWith);
        path.lineTo((float) (getWidth() / 2 - outerCircleRadius * Math.sin(degree)), getHeight() / 2 - outerCircleRadius - teethTopWith);
        path.close();
        float avgAngle = 360f / teethCount;
        for (int i = 0; i < teethCount; i++) {
            canvas.save();
            canvas.rotate(i * avgAngle, getWidth() / 2, getHeight() / 2);
            canvas.drawPath(path, gearPaint);
            canvas.restore();
        }
        canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, outerCircleRadius, outerPaint);
        canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, innerCircleRadius, innerPaint);
    }

    public void apply(GearBuilder builder) {
        teethColor = builder.teethColor == null ? Color.WHITE : builder.teethColor;
        innerCircleColor = builder.innerColor == null ? Color.WHITE : builder.innerColor;
        outerCircleColor = builder.outerColor == null ? Color.YELLOW : builder.outerColor;
        duration = builder.duration > 0 ? builder.duration : 4000;
    }

    public static class GearBuilder {
        private IComponentCallback iComponentCallback;
        private Color teethColor;
        private Color innerColor;
        private Color outerColor;
        private int duration;

        public GearBuilder(IComponentCallback iComponentCallback) {
            this.iComponentCallback = iComponentCallback;
        }

        public GearBuilder setTeethColor(Color teethColor) {
            this.teethColor = teethColor;
            return this;
        }

        public GearBuilder setInnerColor(Color innerColor) {
            this.innerColor = innerColor;
            return this;
        }

        public GearBuilder setOuterColor(Color outerColor) {
            this.outerColor = outerColor;
            return this;
        }

        public GearBuilder setDuration(int duration) {
            this.duration = duration;
            return this;
        }

        public GearElement build() {
            GearElement gearElement = new GearElement(iComponentCallback);
            gearElement.apply(this);
            return gearElement;
        }
    }
}
